package com.xhwl.logistics.service.cent.server;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xhwl.common.dto.cent.vehicle.feign.*;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.Project;
import com.xhwl.common.pojo.cent.vehicle.VehcPayRecord;
import com.xhwl.common.pojo.cent.vehicle.bo.bi.VehicleAccessRecordTotalStatisticsBO;
import com.xhwl.common.pojo.cent.vehicle.bo.http.ParkingLotPayRecordBO;
import com.xhwl.common.pojo.cent.vehicle.bo.http.PayRecordBO;
import com.xhwl.common.utils.ChkUtil;
import com.xhwl.logistics.bo.VehicleAccessRecordBO;
import com.xhwl.logistics.bo.input.PageBO;
import com.xhwl.logistics.bo.input.QueryVehicleAccessRecordBO;
import com.xhwl.logistics.component.VehicleHomeAddressProperty;
import com.xhwl.logistics.converter.ToPageBO;
import com.xhwl.logistics.converter.ToPageVO;
import com.xhwl.logistics.converter.ToVehicleAccessRecordVO;
import com.xhwl.logistics.converter.mapstruct.VehicleAccessRecordConverter;
import com.xhwl.logistics.dao.mapper.IVehicleAccessRecordMapper;
import com.xhwl.logistics.entity.VehicleAccessRecord;
import com.xhwl.logistics.service.IVehicleAccessRecordService;
import com.xhwl.logistics.service.business.VehicleCommonBusinessService;
import com.xhwl.logistics.service.impl.VehcPayRecordServiceImpl;
import com.xhwl.logistics.service.impl.VehicleAccessRecordServiceImpl;
import com.xhwl.logistics.util.AboutDateUtil;
import com.xhwl.logistics.util.MathUtil;
import com.xhwl.logistics.vo.PageVO;
import com.xhwl.logistics.vo.VehicleAccessRecordAnotherVO;
import com.xhwl.logistics.vo.VehicleStatisticsDateVO;
import com.xhwl.logistics.vo.unique.VehicleUniqueAolaiAccessRecordTotalVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
//@Service
public class VehicleAccessRecordFeignServiceImpl implements IVehicleAccessRecordFeignService {

    @Autowired
    private IVehicleAccessRecordMapper vehicleAccessRecordMapper;

    @Autowired
    private IVehicleAccessRecordService vehicleAccessRecordService;

    @Autowired
    private VehicleAccessRecordConverter vehicleAccessRecordConverter;

    @Autowired
    private ToPageBO toPageBO;

    @Autowired
    private ToVehicleAccessRecordVO toVehicleAccessRecordVO;

    @Autowired
    private VehicleCommonBusinessService vehicleCommonBusinessService;

    @Autowired
    private VehcPayRecordServiceImpl vehcPayRecordService;

    @Autowired
    private VehicleAccessRecordServiceImpl vehicleAccessRecordServiceTrue;

    @Autowired
    private VehicleHomeAddressProperty vehicleHomeAddressProperty;

    @Autowired
    private ToPageVO toPageVO;

    /**
     * 青岛奥莱的定制车牌号前缀
     */
    private static final String carA = "山东省青岛市";
    private static final String carB = "山东省日照市";
    private static final String carC = "山东省烟台市";

    private Wrapper<VehicleAccessRecord> conditionForJudgeExistAccessRecordForIn(String plateNumber, Date exitTime) {
        LambdaQueryWrapper<VehicleAccessRecord> lambdaQueryWrapper = Wrappers.lambdaQuery();
        return lambdaQueryWrapper
                .eq(VehicleAccessRecord::getPlateNumber, plateNumber)
                .lt(VehicleAccessRecord::getEnterTime, exitTime)
                .orderByDesc(VehicleAccessRecord::getId)
                .last("limit 1");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPayRecords(ParkingLotPayRecordBO parkingLotPayRecordBO) {
        log.info("start: cent-logistics add pay record feign");
        List<PayRecordBO> pay = parkingLotPayRecordBO.getPayRecordBOList();

        if (ChkUtil.isNotNull(pay)) {
            Integer projectId = pay.get(0).getProjectId();
            List<VehcPayRecord> oldList = vehcPayRecordService.list(new LambdaQueryWrapper<VehcPayRecord>()
                    .eq(VehcPayRecord::getProjectId, projectId)
                    .in(VehcPayRecord::getParkId, pay.get(0).getParkId()));

            LinkedList<VehcPayRecord> vehiclePayRecords = new LinkedList<>();
            for (PayRecordBO payRecordBO : pay) {
                // 在该项目的该停车场下，用主账单id + 支付订单号过滤掉数据库中已有的缴费记录
                List<VehcPayRecord> list = oldList.stream()
                        .filter(t -> t.getPaymentOrderNo().equals(payRecordBO.getTranId()) && t.getBillId().equals(payRecordBO.getPayRecordId()))
                        .collect(Collectors.toList());
                if (!list.isEmpty()) {
                    continue;
                }
                VehcPayRecord vehcPayRecord = new VehcPayRecord();
                vehcPayRecord.setProjectId(projectId);
                vehcPayRecord.setParkId(payRecordBO.getParkId());
                vehcPayRecord.setPlateNo(payRecordBO.getPlateNumber());
                vehcPayRecord.setBillId(payRecordBO.getPayRecordId());
                vehcPayRecord.setPaymentOrderNo(payRecordBO.getTranId());
                vehcPayRecord.setEntryTime(payRecordBO.getEnterTime());
                vehcPayRecord.setPayTime(payRecordBO.getPayTime());
                vehcPayRecord.setPayMethod(payRecordBO.getPayMethod());
                vehcPayRecord.setTotalMoney(payRecordBO.getTotalMoney());
                vehcPayRecord.setPaidMoney(payRecordBO.getPaidMoney());
                vehcPayRecord.setPlateColor(payRecordBO.getPlateColor());
                vehcPayRecord.setFreeTime(payRecordBO.getDeductedHours());
                vehcPayRecord.setFreeMoney(payRecordBO.getDeductedAmount());
                vehcPayRecord.setOrderNo(payRecordBO.getOrderNumber());
                vehcPayRecord.setPayType(payRecordBO.getPayType());
                vehcPayRecord.setPaySource(payRecordBO.getPaySource());
                vehiclePayRecords.add(vehcPayRecord);
            }
            vehcPayRecordService.saveBatch(vehiclePayRecords);
            log.info("end: cent-logistics add pay record feign");
        } else {
            log.info("add pay record error: pay is null");
        }
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addAccessRecordsForIn(CreateVehicleAccessRecordsForInFeignDTO createVehicleAccessRecordsForInFeignDTO) {
        log.info("start: cent-logistics add access record for in feign");
        try {
            List<CreateVehicleAccessRecordForInFeignDTO> in = createVehicleAccessRecordsForInFeignDTO.getIn();
            if(ChkUtil.isNull(in)) {
                return;
            }
            /**
             * 为出行记录添加项目信息，并优化代码
             */
            Project project = new Project();
            if (ChkUtil.isNotNull(in)) {
                project = vehicleCommonBusinessService.getProjectById(in.get(0).getProjectId());
            }

            List<VehicleAccessRecord> oldList = vehicleAccessRecordServiceTrue.list(new LambdaQueryWrapper<VehicleAccessRecord>()
                    .eq(VehicleAccessRecord::getProjectId, project.getId())
                    .eq(VehicleAccessRecord::getParkId, in.get(0).getParkId()));
            List<String> recordIdList = oldList.stream().filter(Objects::nonNull).map(VehicleAccessRecord::getRecordId).collect(Collectors.toList());

            LinkedList<VehicleAccessRecord> vehicleAccessRecords = new LinkedList<>();
            for (CreateVehicleAccessRecordForInFeignDTO createVehicleAccessRecordForInFeignDTO : in) {
                VehicleAccessRecord vehicleAccessRecord = vehicleAccessRecordConverter.toVehicleAccessRecord(createVehicleAccessRecordForInFeignDTO, 0, project.getName(), project.getCode());
                if (!recordIdList.contains(vehicleAccessRecord.getRecordId())) {
                        vehicleAccessRecords.add(vehicleAccessRecord);
                }
            }
            vehicleAccessRecordServiceTrue.saveBatch(vehicleAccessRecords);
        } catch (Exception e) {
            log.error("保存入场记录异常:{}", e);
            throw new BusinessException("保存入场记录异常", e);
        }
        log.info("end: cent-logistics add access record for in feign");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addAccessRecordsForOut(CreateVehicleAccessRecordsForOutFeignDTO createVehicleAccessRecordsForOutFeignDTO) {
        log.info("start: cent-logistics add access record for out feign");
        try {
            List<CreateVehicleAccessRecordForOutFeignDTO> out = createVehicleAccessRecordsForOutFeignDTO.getOut();

            /**
             * 为出行记录添加项目信息,并优化代码
             */
            Project project = new Project();
            if (ChkUtil.isNotNull(out)) {
                project = vehicleCommonBusinessService.getProjectById(out.get(0).getProjectId());
            }
            LinkedList<VehicleAccessRecord> update = new LinkedList<>();
            LinkedList<VehicleAccessRecord> add = new LinkedList<>();
            List<VehicleAccessRecord> vehicleAccessRecordList = vehicleAccessRecordServiceTrue.list(
                    new LambdaQueryWrapper<VehicleAccessRecord>().eq(VehicleAccessRecord::getProjectId, out.get(0).getProjectId())
                            .orderByDesc(VehicleAccessRecord::getId));
            for (CreateVehicleAccessRecordForOutFeignDTO createVehicleAccessRecordForOutFeignDTO : out) {
                String plateNumber = createVehicleAccessRecordForOutFeignDTO.getPlateNumber();
                Date exitTime = createVehicleAccessRecordForOutFeignDTO.getExitTime();
                String recordId = createVehicleAccessRecordForOutFeignDTO.getRecordId();
                VehicleAccessRecord vehicleAccessRecord = null;
                if (recordId == null) {
                    vehicleAccessRecord = vehicleAccessRecordList.stream().filter(s -> {
                        if (StringUtils.equals(s.getPlateNumber(), plateNumber) &&
                                s.getEnterTime().compareTo(exitTime) == -1) {
                            return true;
                        } else {
                            return false;
                        }
                    }).findAny().orElse(null);
                } else {
                    vehicleAccessRecord = vehicleAccessRecordList.stream().filter(s -> {
                        if (StringUtils.equals(s.getRecordId(), recordId)) {
                            return true;
                        } else {
                            return false;
                        }
                    }).findAny().orElse(null);
                }
                if (vehicleAccessRecord == null) {
                    VehicleAccessRecord vehicleAccessRecord1 = toVehicleAccessRecord(createVehicleAccessRecordForOutFeignDTO, 1, project.getName(), project.getCode());
                    add.add(vehicleAccessRecord1);
                } else {
                    VehicleAccessRecord vehicleAccessRecord1 = toVehicleAccessRecord(createVehicleAccessRecordForOutFeignDTO, vehicleAccessRecord.getId(), 1);
                    update.add(vehicleAccessRecord1);
                }
            }
            vehicleAccessRecordServiceTrue.saveBatch(add);
            vehicleAccessRecordServiceTrue.updateBatchById(update);
            log.info("end: cent-logistics add access record for out feign");
        } catch (Exception e) {
            throw new BusinessException("保存出行记录异常", e);
        }
    }

    @Override
    public PageVO<VehicleAccessRecordAnotherVO> queryAccessRecords(VehicleAccessRecordQuery vehicleAccessRecordQuery) {

        QueryVehicleAccessRecordBO queryVehicleAccessRecordBO = vehicleAccessRecordConverter.vehicleAccessRecordQuery2QueryVehicleAccessRecordBO(vehicleAccessRecordQuery);
        PageBO pageBO = toPageBO.toPageBOForAccessRecord(vehicleAccessRecordConverter.vehiclePageQuery2PageDTO(vehicleAccessRecordQuery));

        IPage<VehicleAccessRecordBO> vehicleAccessRecordBOIPage = vehicleAccessRecordService.accessRecord(queryVehicleAccessRecordBO, pageBO);

        return toPageVO.toPageVO(vehicleAccessRecordBOIPage, toVehicleAccessRecordVO.toVehicleAccessRecordAnotherVOList(vehicleAccessRecordBOIPage.getRecords()));
    }

    @Override
    public ResultJson<VehicleAccessRecordTotalStatisticsBO> queryAccessStatistics(VehicleTotalStatisticsQuery statisticsQuery) {
        if (statisticsQuery.getTimeRangeType() != null && statisticsQuery.getTimeRangeType() == 1) {
            String datetime = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            return ResultJson.success(vehicleAccessRecordMapper.getAccessRecordStatistics(statisticsQuery.getProjectId(), datetime));
        }
        return ResultJson.success();
    }

    @Override
    public ResultJson<List<VehicleStatisticsDateVO>> queryAccessStatisticsTrend(VehicleTotalStatisticsQuery statisticsQuery) {
        if (statisticsQuery.getTimeRangeType() == 1) {
            String datetime = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            return ResultJson.success(vehicleAccessRecordMapper.getAccessRecordStatisticsTrend(statisticsQuery.getProjectId(), statisticsQuery.getTimeRangeType(), datetime));
        }
        if (statisticsQuery.getTimeRangeType() == 2) {
            String datetime = new SimpleDateFormat("yyyy-MM-01").format(new Date());
            return ResultJson.success(vehicleAccessRecordMapper.getAccessRecordStatisticsTrend(statisticsQuery.getProjectId(), statisticsQuery.getTimeRangeType(), datetime));
        }
        return ResultJson.success();
    }

    /**
     * 青岛奥莱定制化接口，获取入园车辆分布，鲁B、Y和L，具体实现类
     */
    @Override
    public ResultJson getUniqueAccessRecordTotal(VehicleParkingLotQuery vehicleParkingLotQuery) {
        VehicleUniqueAolaiAccessRecordTotalVO vehicleUniqueAolaiAccessRecordTotalVO = new VehicleUniqueAolaiAccessRecordTotalVO();

        Date endTime = new Date();
        Date startTime = AboutDateUtil.theSameDayOfDate(endTime);
        List<VehicleAccessRecord> vehicleAccessRecordList = vehicleAccessRecordServiceTrue.list(
                conditionForCarInFromProjectIdAndTime(vehicleParkingLotQuery.getProjectId(), startTime, endTime));
        if (vehicleAccessRecordList.isEmpty()) {
            return ResultJson.successWithResult(vehicleUniqueAolaiAccessRecordTotalVO);
        }
        vehicleUniqueAolaiAccessRecordTotalVO.setTotalCar(vehicleAccessRecordList.size());

        //求出相应的入园车辆数
        List<VehicleAccessRecord> vehicleAccessRecordsCarA = this.calculateAccessRecordFromPrePlateNumber(vehicleAccessRecordList, vehicleHomeAddressProperty.getLocalPlateName(carA));
        List<VehicleAccessRecord> vehicleAccessRecordsCarB = this.calculateAccessRecordFromPrePlateNumber(vehicleAccessRecordList, vehicleHomeAddressProperty.getLocalPlateName(carB));
        List<VehicleAccessRecord> vehicleAccessRecordsCarC = this.calculateAccessRecordFromPrePlateNumber(vehicleAccessRecordList, vehicleHomeAddressProperty.getLocalPlateName(carC));

        vehicleUniqueAolaiAccessRecordTotalVO.setPartAcar(vehicleAccessRecordsCarA.size());
        vehicleUniqueAolaiAccessRecordTotalVO.setPartBcar(vehicleAccessRecordsCarB.size());
        vehicleUniqueAolaiAccessRecordTotalVO.setPartCcar(vehicleAccessRecordsCarC.size());
        Integer partOtherCar = vehicleAccessRecordList.size() - vehicleAccessRecordsCarA.size() - vehicleAccessRecordsCarB.size() - vehicleAccessRecordsCarC.size();
        vehicleUniqueAolaiAccessRecordTotalVO.setPartOtherCar(partOtherCar);

        //求出入园车辆的占比
        vehicleUniqueAolaiAccessRecordTotalVO.setRateAcar(MathUtil.getRateFromInterger(vehicleAccessRecordList.size(), vehicleAccessRecordsCarA.size(), true));
        vehicleUniqueAolaiAccessRecordTotalVO.setRateBcar(MathUtil.getRateFromInterger(vehicleAccessRecordList.size(), vehicleAccessRecordsCarB.size(), true));
        vehicleUniqueAolaiAccessRecordTotalVO.setRateCcar(MathUtil.getRateFromInterger(vehicleAccessRecordList.size(), vehicleAccessRecordsCarC.size(), true));
        vehicleUniqueAolaiAccessRecordTotalVO.setRateOtherCar(MathUtil.getRateFromInterger(vehicleAccessRecordList.size(), partOtherCar, true));
        return ResultJson.successWithResult(vehicleUniqueAolaiAccessRecordTotalVO);
    }


    /**
     * 根据项目id和时间查询进记录的条件
     */
    private Wrapper<VehicleAccessRecord> conditionForCarInFromProjectIdAndTime(Integer projectId, Date startTime, Date endTime) {
        return new LambdaQueryWrapper<VehicleAccessRecord>()
                .eq(VehicleAccessRecord::getProjectId, projectId)
                .between(VehicleAccessRecord::getEnterTime, startTime, endTime);
    }

    /**
     * 根据出行记录集合，求出满足某个车牌号前缀的出行记录集合
     */
    private List<VehicleAccessRecord> calculateAccessRecordFromPrePlateNumber(List<VehicleAccessRecord> vehicleAccessRecordList, String prePlateNumber) {
        return vehicleAccessRecordList.stream().filter(
                vehicleAccessRecord -> {
                    String[] plateNumbers = prePlateNumber.split(",");
                    for (String plateNumber : plateNumbers) {
                        if (vehicleAccessRecord.getPlateNumber().contains(plateNumber)) {
                            return true;
                        }
                    }
                    return false;
                }
        ).collect(Collectors.toList());
    }

    private VehicleAccessRecord toVehicleAccessRecord(CreateVehicleAccessRecordForOutFeignDTO createVehicleAccessRecordForOutFeignDTO, Integer status, String projectName, String projectCode) {

        VehicleAccessRecord vehicleAccessRecord = new VehicleAccessRecord();

        if (createVehicleAccessRecordForOutFeignDTO != null) {
            vehicleAccessRecord.setProjectId(createVehicleAccessRecordForOutFeignDTO.getProjectId());
            vehicleAccessRecord.setParkId(createVehicleAccessRecordForOutFeignDTO.getParkId());
            vehicleAccessRecord.setPlateNumber(createVehicleAccessRecordForOutFeignDTO.getPlateNumber());
            vehicleAccessRecord.setCardType(createVehicleAccessRecordForOutFeignDTO.getCardType());
            vehicleAccessRecord.setExitTime(createVehicleAccessRecordForOutFeignDTO.getExitTime());
            vehicleAccessRecord.setExitType(createVehicleAccessRecordForOutFeignDTO.getExitType());
            vehicleAccessRecord.setExitPictureUrl(createVehicleAccessRecordForOutFeignDTO.getExitPictureUrl());
            vehicleAccessRecord.setExitPassageName(createVehicleAccessRecordForOutFeignDTO.getExitPassageName());
            vehicleAccessRecord.setRecordId(createVehicleAccessRecordForOutFeignDTO.getRecordId());
            vehicleAccessRecord.setPlateColor(createVehicleAccessRecordForOutFeignDTO.getPlateColor());
        }

        if (createVehicleAccessRecordForOutFeignDTO.getEnterPictureUrl2() != null) {
            vehicleAccessRecord.setEnterPictureUrl(createVehicleAccessRecordForOutFeignDTO.getEnterPictureUrl2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterTime2() != null) {
            vehicleAccessRecord.setEnterTime(createVehicleAccessRecordForOutFeignDTO.getEnterTime2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterPassageName2() != null) {
            vehicleAccessRecord.setEnterPassageName(createVehicleAccessRecordForOutFeignDTO.getEnterPassageName2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterType2() != null) {
            vehicleAccessRecord.setEnterType(createVehicleAccessRecordForOutFeignDTO.getEnterType2());
        }
        if (status != null) {
            vehicleAccessRecord.setStatus(status);
        }
        if (projectName != null) {
            vehicleAccessRecord.setProjectName(projectName);
        }
        if (projectCode != null) {
            vehicleAccessRecord.setProjectCode(projectCode);
        }

        return vehicleAccessRecord;
    }

    private VehicleAccessRecord toVehicleAccessRecord(CreateVehicleAccessRecordForOutFeignDTO createVehicleAccessRecordForOutFeignDTO, Integer id, Integer status) {

        VehicleAccessRecord vehicleAccessRecord = new VehicleAccessRecord();

        if (createVehicleAccessRecordForOutFeignDTO != null) {
            vehicleAccessRecord.setExitTime(createVehicleAccessRecordForOutFeignDTO.getExitTime());
            vehicleAccessRecord.setExitType(createVehicleAccessRecordForOutFeignDTO.getExitType());
            vehicleAccessRecord.setExitPictureUrl(createVehicleAccessRecordForOutFeignDTO.getExitPictureUrl());
            vehicleAccessRecord.setExitPassageName(createVehicleAccessRecordForOutFeignDTO.getExitPassageName());
            vehicleAccessRecord.setPlateColor(createVehicleAccessRecordForOutFeignDTO.getPlateColor());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterPictureUrl2() != null) {
            vehicleAccessRecord.setEnterPictureUrl(createVehicleAccessRecordForOutFeignDTO.getEnterPictureUrl2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterTime2() != null) {
            vehicleAccessRecord.setEnterTime(createVehicleAccessRecordForOutFeignDTO.getEnterTime2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterPassageName2() != null) {
            vehicleAccessRecord.setEnterPassageName(createVehicleAccessRecordForOutFeignDTO.getEnterPassageName2());
        }
        if (createVehicleAccessRecordForOutFeignDTO.getEnterType2() != null) {
            vehicleAccessRecord.setEnterType(createVehicleAccessRecordForOutFeignDTO.getEnterType2());
        }
        if (id != null) {
            vehicleAccessRecord.setId(id);
        }
        if (status != null) {
            vehicleAccessRecord.setStatus(status);
        }

        return vehicleAccessRecord;
    }
}
